package org.xx.armory.doc;


import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static org.xx.armory.commons.Validators.rejectIfBlank;

/**
 * 模板数据上下文, 包含了使用模板输出时使用的数据。
 *
 * @author Haart
 */
public final class TemplateContext
        implements Iterable<String> {
    private final Map<String, Object> data;

    /**
     * 构造模板上下文。
     */
    public TemplateContext() {
        this.data = new HashMap<>();
    }

    /**
     * 构造模板上下文。
     *
     * @param map
     *         模板上下文包含的数据。
     */
    public TemplateContext(
            Map<String, Object> map
    ) {
        this.data = map == null ? new HashMap<>() : new HashMap<>(map);
    }

    /**
     * 将键正规化。
     *
     * @param key
     *         键名。
     * @return 正规化并且转为小写的键名。
     * @throws NullPointerException
     *         如果参数{@code key}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code key}只包含空白字符。
     */
    private static String ensureKey(
            String key
    ) {
        return rejectIfBlank(key, "key").trim().toLowerCase();
    }

    public final Object get(
            String key
    ) {
        return this.data.get(ensureKey(key));
    }

    public final String getString(
            String key
    ) {
        final Object value = this.data.get(ensureKey(key));
        return value != null ? (String) value : "";
    }

    public final Object get(
            String key,
            int index
    ) {
        final Object value = this.data.get(ensureKey(key));
        return Array.get(value, index);
    }

    public final String getString(
            String key,
            int index
    ) {
        final Object arrayValue = this.data.get(ensureKey(key));
        final Object itemValue = Array.get(arrayValue, index);
        return itemValue != null ? (String) itemValue : "";
    }

    public final int getArraySize(
            String key
    ) {
        final Object arrayValue = this.data.get(ensureKey(key));
        if (arrayValue != null && arrayValue.getClass().isArray()) {
            return Array.getLength(arrayValue);
        } else {
            return -1;
        }
    }

    public final Object put(
            String key,
            Object value
    ) {
        return this.data.put(ensureKey(key), value);
    }

    public final Object put(
            String key,
            int index,
            Object value
    ) {
        final Object arrayValue = this.data.get(ensureKey(key));
        final Object itemValue = Array.get(arrayValue, index);
        Array.set(arrayValue, index, value);
        return itemValue;
    }

    @Override
    public Iterator<String> iterator() {
        return this.data.keySet().iterator();
    }
}
